package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constants.LearningConstant;
import com.tianji.learning.constants.RedisConstant;
import com.tianji.learning.domain.page.PointsBoardQuery;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.TableInfoContext;
import lombok.RequiredArgsConstructor;
import org.apache.ibatis.annotations.One;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 学霸天梯榜 服务实现类
 * </p>
 *
 * @author rui
 * @since 2024-07-29
 */
@Service
@RequiredArgsConstructor
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
    private final StringRedisTemplate redisTemplate;
    private final UserClient userClient;
    @Override
    public PointsBoardVO queryRankBySeasonId(PointsBoardQuery query) {
        //1.获取用户id
        Long userId = UserContext.getUser();

        //2.查询赛季信息获取前百
        Long season = query.getSeason();
        boolean isCurrent =  season == null || season.equals(0L);

        //3.查询当前用户的信息 及赛季信息
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("yyyyMM");
        String format = now.format(timeFormatter);
        String key = RedisConstant.POINTS_BOARDS_KEY_PREFIX + format;
        //todo
        //key = "boards:202302";
        //3.1 通过现在的用户查询现赛季信息或者历史赛季信息，要分页查询，而且是redis缓存
        PointsBoard board = isCurrent?pageQueryCurrentWithUserInfo(userId,query,key)
                : pageQueryPastWithUserInfo(userId,query);

        //3.2 查询赛季分页的数据
        List<PointsBoard> list = isCurrent?pageQueryCurrent(key,query.getPageNo(),query.getPageSize())
                : pageQueryPast(query);

        //4.封装用户信息
        Set<Long> userIds = list.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
        List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if(CollUtil.isNotEmpty(userDTOS)){
            userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, u -> u));
        }

        //5.封装返回信息
        List<PointsBoardItemVO> voList = new ArrayList<>(list.size());
        for (PointsBoard pointsBoard : list) {
            if(pointsBoard != null){
                PointsBoardItemVO vo = new PointsBoardItemVO();
                vo.setPoints(pointsBoard.getPoints());
                vo.setRank(pointsBoard.getRank());
                UserDTO userDTO = userDTOMap.get(pointsBoard.getUserId());
                if(userDTO!=null){
                    vo.setName(userDTO.getName());
                }
                voList.add(vo);
            }
        }
        PointsBoardVO pointsBoardVO = new PointsBoardVO();
        if (board != null) {
            pointsBoardVO.setPoints(board.getPoints());
            pointsBoardVO.setRank(board.getRank());
        }
        pointsBoardVO.setBoardList(voList);
        return pointsBoardVO;
    }

    private List<PointsBoard> pageQueryPast(PointsBoardQuery query) {
       //获取动态表名
        TableInfoContext.setInfo(LearningConstant.POINTS_BOARD_TABLE_PREFIX+query.getSeason());
        //分页查询历史赛季里的top100天梯信息
        List<PointsBoard> records = lambdaQuery()
                .page(query.toMpPage())
                .getRecords();
        if(records.isEmpty()){
            return Collections.emptyList();
        }
        /**
         * 记得这里的id就是rank 如果存进去就是rank-》id 取就是id -》rank
         */
        records.forEach(b -> b.setRank(b.getId().intValue()));
        //清理动态表名
        TableInfoContext.remove();
        return records;
    }

    public List<PointsBoard> pageQueryCurrent(String key,Integer pageNo,Integer pageSize) {
        //分页查询现在redis缓存里的现天梯信息
        int from = (pageNo - 1) * pageSize; //当前页码
        Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, from, from + pageSize - 1);
        if(CollUtil.isEmpty(typedTuples)){
            return Collections.emptyList();
        }
        List<PointsBoard> pointsBoards = new ArrayList<>();
        int rank = from + 1;
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            PointsBoard vo = new PointsBoard();
            if(typedTuple != null){
                String userId = typedTuple.getValue();
                Double score = typedTuple.getScore();
                vo.setRank(rank);
                if(userId != null && score != null){
                    vo.setPoints(score.intValue());
                    vo.setUserId(Long.valueOf(userId));
                }
                pointsBoards.add(vo);
                rank++;
            }
        }
        return pointsBoards;
    }

    private PointsBoard pageQueryPastWithUserInfo(Long userId, PointsBoardQuery query) {

        if(query == null || userId == null){
            return null;
        }
        TableInfoContext.setInfo(LearningConstant.POINTS_BOARD_TABLE_PREFIX+query.getSeason());
        //在数据库里查询历史赛季榜单查询个人用户信息
        PointsBoard pointsBoard = lambdaQuery()
                .eq(PointsBoard::getUserId, userId)
                .one();
        if(pointsBoard != null){
            pointsBoard.setRank(pointsBoard.getId().intValue());
        }
        TableInfoContext.remove();
        return pointsBoard;
    }

    private PointsBoard pageQueryCurrentWithUserInfo(Long userId, PointsBoardQuery query, String key) {
        //查询当前用户的排名积分
        PointsBoard pointsBoard = new PointsBoard();
        Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
        Double score = redisTemplate.opsForZSet().score(key, userId.toString());
        if (score != null) {
            pointsBoard.setPoints(score.intValue());
        }
        if (rank != null) {
            pointsBoard.setRank(rank.intValue() + 1);
        }
        return pointsBoard;
    }
    @Override
    public void createPointsBoardTable(Integer id) {
        getBaseMapper().createPointsBoardTable(LearningConstant.POINTS_BOARD_TABLE_PREFIX+id.toString());
    }

}
